#include"GameState.h"
/**
 * creating a state with default game setting
 * @return
 */
GameState::GameState(){
	boardSize = 4;//default size
	depth = 0;
	difficult = 20;
	utility = 0;
}
/**
 * create a state by copying a previous one
 * @param GameState state
 */
GameState::GameState(const GameState &state){
	boardSize = state.boardSize;
	turnNumber =  state.turnNumber;
	ptrState = new int* [boardSize];
	for(int i=0;i<boardSize;i++){
		ptrState[i] = new int[boardSize];
		for(int j=0;j<boardSize;j++){
			ptrState[i][j] = state.ptrState[i][j];
		}
	}
	difficult = state.difficult;
	depth = state.depth;
	utility = state.utility;
}
/**
 * create a state from gameSetting
 * @param GameSetting setting
 *
 */
GameState::GameState(const GameSetting &setting){
	if(setting.boardSize<=10&&setting.boardSize>=4&&setting.boardSize%2==0){
		boardSize = setting.boardSize;
	}
	else{
		boardSize = 4;
	}
	ptrState = new int* [boardSize];
	for(int i=0;i < boardSize; i++){
		ptrState[i] = new int[boardSize];
		for(int j=0;j<boardSize;j++){
			ptrState[i][j] = 0;
		}
	}
	int middle = boardSize/2;
	ptrState[middle][middle] = ptrState[middle-1][middle-1] = 1;
	ptrState[middle-1][middle] = ptrState[middle][middle-1] = -1;
	if(setting.playFirst== true){
		turnNumber =-1;
	}else{
		turnNumber = 1;
	}
	difficult = setting.difficultLevel;
	depth = 0;
}

/**
 * get the utility value of current state;
 * @return int value;
 */
int GameState::getStateValue(){
	int value = 0;
	for(int i=0;i<boardSize;i++){
		for(int j=0;j<boardSize;j++){
			value+= ptrState[i][j];
		}
	}
	return value;
}


/**
 * return whether action(x,y) is a valid move;
 * @param x
 * @param y
 * @param state
 * @return true if valid;otherwise, false
 */
bool GameState::isValidNextStep(const int &x,const int &y){
	if(x>=0&&y>=0&&x<boardSize&&y<boardSize){
		if(ptrState[x][y] != 0) return false;
		int dx[] = {-1,0,1};
		int dy[] = {-1,0,1};
		for(int m=0;m<=2;m++){
			for(int n=0;n<=2;n++){
				if(x+dx[m]>=boardSize||x+dx[m]<0||y+dy[n]>=boardSize||y+dy[n]<0)
					continue;
				if(ptrState[x+dx[m]][y+dy[n]] == -turnNumber){
					for(int i=x+dx[m], j=y+dy[n];(i>=0 && i< boardSize &&j>=0 && j<boardSize);)
					{
						if(ptrState[i][j] == turnNumber){
							return true;
						}
						i+=dx[m];j+=dy[n];
					}
				}
			}
		}
	}
	return false;
}

/**
 * judge whether there is available move for one side
 * @return true / false
 */
bool GameState::existValidMove(){
	for(int i=0;i<boardSize;i++){
		for(int j=0;j<boardSize;j++){
			if(isValidNextStep(i,j) ==true){
				return true;
			}
		}
	}
	return false;
}

/**
 * test whether a game is terminated
 * @return true if finished.
 */
bool GameState::testTerminate(){
	//if one side cant move
	if(existValidMove()){
		return false;
	}
	else{
		this->turnNumber = -this->turnNumber;
		if(existValidMove()){
			this->turnNumber = -this->turnNumber;
			return false;
		}
		//if the other side cant move
		else{
			return true;
		}
	}
}
/**
 * count all the action is available for a state;fill the actionListVector
 */
void GameState::getActionList(){
	if(existValidMove() == false){
		actionList.append(Action(-1,-1));
	}else{
		for(int i=0;i<boardSize;i++){
			for(int j=0;j<boardSize;j++){
				if(isValidNextStep(i,j) == true){
					actionList.append(Action(i,j));
				}
			}
		}
	}
}
/**
 * if reach cutoff level;
 * @return true or false
 */
bool GameState::cutOff(){
	if(depth>=difficult){
		return true;
	}else{
		return false;
	}
}
/**
 * judge whether a state is equal to this one
 */
bool GameState::equal(const GameState& state){
	if(state.turnNumber != turnNumber)return false;
	for(int i=0;i<boardSize;i++){
		for(int j=0;j<boardSize;j++){
			if(ptrState[i][j]!=state.ptrState[i][j])return false;
		}
	}
	return true;
}
/**
 * this is to check whether the two state is sysmetric
 * @param GameState state
 * reutrn true if sysmetric
 */
bool GameState::isLikely(const GameState& state){
 	bool sym0 = true;
	bool sym45 = true;
	bool sym90 = true;
	bool sym135 = true;
	for(int i=0;i<boardSize;i++){
		for(int j=0;j<boardSize;j++){
			if(ptrState[i][j]!=state.ptrState[i][boardSize-j-1])sym0 =false;
			if(ptrState[i][j]!=state.ptrState[j][i])sym45 =false;
		    if(ptrState[i][j]!=state.ptrState[boardSize-i-1][j]) sym90 =false;
		 	if(ptrState[i][j]!=state.ptrState[boardSize-i-1][boardSize-j-1])sym135 =false;
		}
	}
	if(sym0||sym45||sym90||sym135){
		return true;
	}else{
		return false;
	}
}
